package com.liliudong.template.biz.service.sys.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liliudong.template.biz.mapper.sys.SysDeptMapper;
import com.liliudong.template.biz.service.sys.SysDeptService;
import com.liliudong.template.biz.service.sys.SysRoleDeptService;
import com.liliudong.template.common.constant.EntityFieldConst;
import com.liliudong.template.common.constant.ExMessageEnum;
import com.liliudong.template.common.convert.sys.SysDeptConvert;
import com.liliudong.template.common.dto.sys.SysDeptAddDTO;
import com.liliudong.template.common.dto.sys.SysDeptUpdateDTO;
import com.liliudong.template.common.entity.sys.SysDept;
import com.liliudong.template.common.exception.BizException;
import com.liliudong.template.common.vo.sys.SysDeptDetailVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * 系统部门服务impl
 *
 * @author ldli5
 * @date 2024/06/21
 */
@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {

	private static final String LIMIT_1 = "limit 1";
	public static final String FIRST_DEPT_NO = "01";
	public static final String TWO_DIGIT_FORMAT = "%02d";

	private final SysRoleDeptService sysRoleDeptService;

	@Override
	public void addOne(SysDeptAddDTO sysDeptAddDTO) {
		SysDept sysDept = SysDeptConvert.INSTANCE.addDto2Entity(sysDeptAddDTO);
		// 相同部门部门下不能部门不能重名
		boolean checkNameSingleWithSameDept = checkNameSingleWithSameDept(sysDept.getName(), sysDept.getParentId());
		if (!checkNameSingleWithSameDept) {
			throw new BizException(ExMessageEnum.DEPT_NAME_REPEAT);
		}
		// 自动生成部门编号 父编号 + 序列
		Long parentId = sysDept.getParentId();
		String nextDeptNo = generateNextDeptNo(parentId);
		sysDept.setDeptNo(nextDeptNo);
		this.save(sysDept);
	}

	@Override
	public void deleteById(Long id) {
		long count = sysRoleDeptService.countByDeptId(id);
		if (count > 0) {
			throw new BizException(ExMessageEnum.DATA_OCCUPIED);
		}
		this.removeById(id);
	}

	@Override
	public void modifyById(Long id, SysDeptUpdateDTO sysDeptUpdateDTO) {
		SysDept sysDept = SysDeptConvert.INSTANCE.updateDto2Entity(sysDeptUpdateDTO);
		// 相同部门部门下不能部门不能重名
		boolean checkNameSingleWithSameDept = checkNameSingleWithSameDept(sysDept.getName(), sysDept.getParentId());
		if (!checkNameSingleWithSameDept) {
			throw new BizException(ExMessageEnum.DEPT_NAME_REPEAT);
		}
		sysDept.setId(id);
		this.updateById(sysDept);
	}

	@Override
	public List<Tree<Long>> tree() {
		List<SysDept> sysDeptList = list();
		return TreeUtil.build(sysDeptList, 0L, (sysDept, tree) -> {
			String deptNo = sysDept.getDeptNo();
			String name = sysDept.getName();
			Long parentId = sysDept.getParentId();
			Long id = sysDept.getId();
			LocalDateTime createdAt = sysDept.getCreatedAt();
			LocalDateTime updatedAt = sysDept.getUpdatedAt();

			tree.setId(id);
			tree.setParentId(parentId);
			tree.setName(name);
			tree.putExtra(EntityFieldConst.DEPT_NO, deptNo);
			tree.putExtra(EntityFieldConst.CREATED_AT, createdAt);
			tree.putExtra(EntityFieldConst.UPDATED_AT, updatedAt);
		});
	}

	@Override
	public SysDeptDetailVO detailById(Long id) {
		SysDept sysDept = getById(id);
		return SysDeptConvert.INSTANCE.entity2DetailVo(sysDept);
	}

	/**
	 * 生成下一个部门编号
	 *
	 * @param parentId 父id
	 * @return {@link String }
	 */
	private synchronized String generateNextDeptNo(Long parentId) {
		SysDept sysDeptLatest = getOne(
				lambdaQuery()
						.select(SysDept::getDeptNo)
						.eq(SysDept::getParentId, parentId)
						.orderByDesc(SysDept::getCreatedAt)
						.last(LIMIT_1)
						.getWrapper()
		);
		if (Objects.isNull(sysDeptLatest)) {
			SysDept sysDeptParent = getById(parentId);
			String parentDeptNo = sysDeptParent.getDeptNo();
			return parentDeptNo + FIRST_DEPT_NO;
		}
		String latestDeptNo = sysDeptLatest.getDeptNo();
		String parentDeptNo = latestDeptNo.substring(0, latestDeptNo.length() - 2);
		String sequence = latestDeptNo.length() == 2 ? latestDeptNo : latestDeptNo.substring(latestDeptNo.length() - 2);
		return parentDeptNo + String.format(TWO_DIGIT_FORMAT, Integer.parseInt(sequence) + 1);
	}


	/**
	 * 检查同一部门单个名称
	 *
	 * @param name     名称
	 * @param parentId 父id
	 * @return boolean
	 */
	private boolean checkNameSingleWithSameDept(String name, Long parentId) {
		return count(
				lambdaQuery()
						.eq(SysDept::getParentId, parentId)
						.eq(SysDept::getName, name)
						.getWrapper()
		) <= 0;
	}
}
